#include "stdafx.h"
#include "Control.h"

using namespace mgui;
using namespace input;

Control::Control()
	: IsVisible(true), mBounds(0, 0, 0, 0), mHasBounds(false), mExclusiveInputReceiver(NULL)
{
	mRootControl = this;
}

Control::~Control()
{
	for(auto it = mChildren.begin(); it != mChildren.end(); ++it)
		delete *it;
}

void Control::addListener(int eventType, std::function<void (const EventArgs&)> listener)
{
	mListeners.push_back(std::make_pair(eventType, listener));
}

void Control::addChild(Control & child)
{
	child.mBounds.X += mBounds.X;
	child.mBounds.Y += mBounds.Y;

	child.setRootControl(*mRootControl);

	mChildren.push_back(&child);
}

void mgui::Control::draw()
{
	if(!IsVisible)
		return;

	drawSelf();

	for(auto it = mChildren.begin(); it != mChildren.end(); ++it)
		(*it)->draw();
}

bool Control::leftButtonDown(const Point & pt)
{
	if(!IsVisible)
		return false;

	if(mExclusiveInputReceiver)
		return mExclusiveInputReceiver->leftButtonDown(pt);

	bool processed = false;

	if(!mHasBounds || pointInRect(pt, mBounds))
		processed = processLButtonDownInside(pt);
	else
		processed = processLButtonDownOutside(pt);

	for(auto it = mChildren.begin(); it != mChildren.end(); ++it)
	{
		bool processedByChild = (*it)->leftButtonDown(pt);
		processed = processed | processedByChild;
	}

	return processed;
}

bool Control::leftButtonUp(const Point & pt)
{
	if(!IsVisible)
		return false;

	if(mExclusiveInputReceiver)
		return mExclusiveInputReceiver->leftButtonUp(pt);

	bool processed = false;

	if(!mHasBounds || pointInRect(pt, mBounds))
		processed = processLButtonUpInside(pt);
	else
		processed = processLButtonUpOutside(pt);

	for(auto it = mChildren.begin(); it != mChildren.end(); ++it)
	{
		bool processedByChild = (*it)->leftButtonUp(pt);
		processed = processed | processedByChild;
	}

	return processed;
}

bool Control::mouseMoved(const Point & pt)
{
	if(!IsVisible)
		return false;

	if(mExclusiveInputReceiver)
		return mExclusiveInputReceiver->mouseMoved(pt);
	
	bool processed = false;

	if(!mHasBounds || pointInRect(pt, mBounds))
		processed = processMouseMovedInside(pt);
	else
		processed = processMouseMovedOutside(pt);

	for(auto it = mChildren.begin(); it != mChildren.end(); ++it)
	{
		bool processedByChild = (*it)->mouseMoved(pt);
		processed = processed | processedByChild;
	}

	return processed;
}

bool Control::keyPressed( const KeyEvent & key )
{
	if(!IsVisible)
		return false;

	if(mExclusiveInputReceiver)
		return mExclusiveInputReceiver->keyPressed(key);

	bool processed = processKeyPressed(key);

	for(auto it = mChildren.begin(); it != mChildren.end(); ++it)
	{
		bool processedByChild = (*it)->keyPressed(key);
		processed = processed | processedByChild;
	}

	return processed;
}

bool Control::setExclusiveInputReceiver( Control & control )
{
	if(mExclusiveInputReceiver == NULL)
	{
		mExclusiveInputReceiver = &control;
		return true;
	}
	return false;
}

bool Control::unsetExclusiveInputReceiver( Control & control )
{
	if(mExclusiveInputReceiver == &control)
	{
		mExclusiveInputReceiver = NULL;
		return true;
	}
	return false;
}

void Control::setRootControl( Control & control )
{
	mRootControl = &control;
	for(auto it = mChildren.begin(); it != mChildren.end(); ++it)
		(*it)->setRootControl(control);
}

void Control::callListeners(int eventType, const EventArgs & args)
{
	for(auto it = mListeners.begin(); it != mListeners.end(); ++it)
		if((*it).first == eventType)
			(*it).second(args);
}

void Control::setBounds(const Rect & bounds)
{
	mBounds = bounds;
	mHasBounds = true;
}